# !/usr/bin/env python
# encoding: utf-8


"""
  @author: gaogao
  @file: Heater P-V.py
  @time: 2022/3/30 15:51
  @desc:
"""
import time
import datetime
from math import *
from ATS.hardwarescan import conf_file_manager
from utils.save_setting_2_ini import save_ini_info
from ATS.application.LCR_App.U2722A_App import U2722A_App
from ATS.application.LCR_App.B2901BL_App import B2901BLApp
from ATS.application.LASER_App.L8164B_App import L8164B_App
from ATS.application.LASER_App.N7744C_App import N7744C_App
from ATS.datamanager import data_transfer_station as DataTransferStation
from utils.read_ini_2_dict import get_option_value, get_refrence_data, get_loss_data
from utils.get_wave_power_util import get_wave_power_value, get_wave_loss_gc
from ATS.application.VNA_App.N5225B_App import N5225BApp
from ATS.util.calcu_step_util import get_points_list
from ATS.util.save_data_2_csv_util import saveData2CSV
from utils.find3db_util import find3db_util
from collections import namedtuple
from matplotlib import pyplot as plt
import numpy as np
from utils.log_util import loggings
from gui import constant
from gui.driver.var_manager import VarManager
from utils.save_data_2_file import save_spot_data_2_file
from database.db_interface import insert_chip
try:
    from ATS.switchdriver.LightSwitchDriver import LightSwitchDriver
except Exception as e:
    raise ValueError("光开关不在线，请重启光开关！")


# 通道1设置扫描电压，通道2、3固定电压
def pv_test(para):
    try:
        result_data = namedtuple("result_data",
                                 "subdie,test_item,curve_type,y_invert,title,x_label,y_label,test_result")
        inst_light = LightSwitchDriver.instance()
        if inst_light.is_connected:
            inst_light.set_all_switch("01", "05")
            time.sleep(1)
            loggings.info("switch" + str(inst_light.query_switch()))
        else:
            inst_light.connect()
        l8164 = para.l8164_setting
        n7744 = para.n7744_setting
        l8164b_app = L8164B_App(l8164["title"])
        n7744c_app = N7744C_App(n7744["title"])
        wave_length = l8164["wave_length"][0]
        l8164b_app.set_power_unit()
        l8164b_app.set_power_value(float(l8164["power_value"]))
        l8164b_app.set_wave_length(int(wave_length))
        time.sleep(int(para.l8164_setting["stable_time"]))
        p_in = l8164b_app.fetch_input_power()
        l8164b_app.output_on()
        n7744c_app.reset()
        n7744c_app.set_power_wave_length()
        n7744c_app.set_power_unit()
        n7744c_app.set_power_range_auto()
        n7744c_app.set_power_atim(n7744["atim"])

        time.sleep(5)

        smu_setting = para.smu_setting
        smu_dict = {}
        # smu voltage_list channel nplc current_range current_limit //mode sweep
        #
        
        b29smu_dict = {}
        init_b29_set_list = []
        b29_set_voltage_list = []
        mes_plans_dict = {"var_func": None, "var1": None, "measure_func": None}
        init_set_list = []
        channel_close_list = []
        if smu_setting:
            for smu in smu_setting:
                if smu["smu"] == "SMU10" or smu["smu"] == "SMU11":
                    if smu["smu"] not in b29smu_dict:
                        b29smu_dict[smu["smu"]] = B2901BLApp(smu["smu"])
                    current_inst = b29smu_dict[smu["smu"]]
                    bias_voltage = smu["voltage_list"][0]
                    current_limit = smu["current_limit"]
                    init_b29_set_list += [lambda inst_obj=current_inst, voltage=bias_voltage,
                                                 current_limit=current_limit: inst_obj.spot_setting(
                        float(voltage), current_limit)]

                    # b29_set_voltage_list += [
                    #     lambda x, inst_obj=current_inst, voltage=bias_voltage: inst_obj.set_voltage(
                    #         float(voltage) + float(x))]
                    # B2901BLApp(smu["smu"]).spot_setting(smu["voltage_list"][0], smu["current_limit"])
                else:
                    if smu["smu"] not in smu_dict:
                        smu_dict[smu["smu"]] = U2722A_App(smu["smu"])
                    current_inst = smu_dict[smu["smu"]]
                    current_voltage_list = smu["voltage_list"]
                    current_channel = smu["channel"]
                    current_channel_nplc = smu["nplc"]
                    current_channel_range = smu["current_range"]
                    current_channel_limit = smu["current_limit"]
                    init_set_list += [lambda x=current_channel, inst_obj=current_inst: inst_obj.set_voltage_range(x),
                                      lambda x=current_channel_nplc, y=current_channel,
                                             inst_obj=current_inst: inst_obj.set_current_nplc(x, y),
                                      lambda x=current_channel_range, y=current_channel_limit,
                                             z=current_channel, inst_obj=current_inst: inst_obj.set_current_range_limit(
                                          x,
                                          y,
                                          z)]
                    if smu["mode"] == "sweep":
                        mes_plans_dict["var1"] = current_voltage_list
                        mes_plans_dict["var_func"] = lambda volt, x=current_channel, inst_obj=current_inst: \
                            inst_obj.set_voltage(volt, x)
                        mes_plans_dict["measure_func"] = lambda x=current_channel, inst_obj=current_inst: abs(
                            float(inst_obj.get_current_value(x)))
                    else:
                        init_set_list += [lambda x=current_voltage_list[0], y=current_channel,
                                                 inst_obj=current_inst: inst_obj.set_voltage(x, y)]

                    if smu["is_measure"]:
                        mes_plans_dict["measure_func"] = lambda x=current_channel, inst_obj=current_inst: abs(
                            float(inst_obj.get_current_value(x)))

                    init_set_list += [lambda y=current_channel,
                                             inst_obj=current_inst: inst_obj.output_state(1, y)]

                    channel_close_list += [lambda y=current_channel,
                                                  inst_obj=current_inst: inst_obj.output_state(0, y)]

            # set init
            for inst_set_func in init_set_list:
                inst_set_func()  # 设置SMU

            for b29_set_func in init_b29_set_list:
                b29_set_func()

            # read mes
            # current_list = []  # result list
            power_list = []
            mes_func = mes_plans_dict["measure_func"]
            # print("mes_plans_dict", mes_plans_dict)
            if mes_func:  # mes func不为空
                if mes_plans_dict["var1"]:  # sweep
                    for volt in mes_plans_dict["var1"]:
                        mes_plans_dict["var_func"](volt)
                        time.sleep(0.1)
                        power_value = n7744c_app.get_power_value()
                        power_list.append(float(power_value))
            sweep_list = [float(i) for i in mes_plans_dict["var1"]]
            wave_power_tuple = get_refrence_data()
            loss_section = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_name.split('_')[0]}_GC"
            loss_gc = get_wave_loss_gc(l8164["wave_length"][0], get_loss_data(section=loss_section))
            loss_sys = get_wave_power_value(l8164["wave_length"][0], wave_power_tuple)

            for num_index in range(len(power_list)):
                power_list[num_index] = round(
                    (float(p_in) - power_list[num_index] - float(loss_sys) - 2 * float(loss_gc)), 3)
            title_section = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_number}-{VarManager().subdie_name}-{para.subdie}"

            curve_title = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_number}-{VarManager().subdie_name}-{para.subdie}-{para.test_item}_PV"
            x_label = "Voltage"
            y_label = "Power"
            DataTransferStation.get_DTS().postarraydata("test", result_data(title_section, para.test_item, 'line', True,
                                                                            curve_title, x_label, y_label,
                                                                            (sweep_list, power_list)))

            chip_name = f"{VarManager().subdie_name}"
            wafer_name = VarManager().wafer_name
            shot_position = f"{VarManager().diex},{VarManager().diey}"
            shot_number = VarManager().shot_number
            chip_number = VarManager().subdie_number
            polarization_type = VarManager().polarization_type
            measurement_parameter = f"{para.subdie}_{para.test_item}_PV"
            measurement_data = str([sweep_list, power_list])
            data_unit = ""
            data_type = "Curve"
            insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                              measurement_parameter, measurement_data, data_unit, data_type)

            # 寻找P-V曲线上的3db的电压值和IL值
            datas = find3db_util(sweep_list, power_list)
            print("3.5datas", datas)
            if datas and len(datas) == 4:
                if datas[0] != "" and datas[0] is not None:
                    if mes_plans_dict["var1"]:
                        mes_plans_dict["var_func"](datas[2])
                        if mes_func:
                            current_value = mes_func()
                    # 计算heater电阻
                    heater_resistance = float(datas[2]) / float(current_value)

                    # 设置bias电压
                    half_slope_voltage = datas[0]
                    if mes_plans_dict["var1"]:
                        mes_plans_dict["var_func"](half_slope_voltage)

                    section_prefix = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_name}"

                    title_path = f"{VarManager().save_folder}/{VarManager().wafer_name}"
                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_{para.test_item}_Heater_3dB",
                                          str(half_slope_voltage))

                    measurement_parameter = f"{para.subdie}_{para.test_item}_Heater_3dB"
                    measurement_data = str(half_slope_voltage)
                    data_unit = "V"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)
                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_{para.test_item}_IL", str(datas[3]))

                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_{para.test_item}_HeaterR",
                                          str(heater_resistance))

                    measurement_parameter = f"{para.subdie}_{para.test_item}_IL"
                    measurement_data = str(datas[3])
                    data_unit = "V"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)

                    measurement_parameter = f"{para.subdie}_{para.test_item}_HeaterR"
                    measurement_data = str(heater_resistance)
                    data_unit = "ohm"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)

                    save_ini_info(constant.REMEMBER_VALUE, "remember_value",
                                  f"{section_prefix}_{para.test_item}_Heater_3dB",
                                  str(half_slope_voltage))
                    save_ini_info(constant.REMEMBER_VALUE, "remember_value", f"{section_prefix}_{para.test_item}_IL",
                                  str(datas[3]))
                    save_ini_info(constant.REMEMBER_VALUE, "remember_value",
                                  f"{section_prefix}_{para.test_item}_HeaterR",
                                  str(heater_resistance))

                    inst_light.set_all_switch("01", "06")
                    time.sleep(1)
                    loggings.info("switch" + str(inst_light.query_switch()))
                    #
                    n5225b = N5225BApp("VNA")
                    n5225b.start_trigger()
                    time.sleep(27)
                    bw, refren_value = n5225b.search_bw()
                    save_ini_info(constant.REMEMBER_VALUE, "remember_value", f"{section_prefix}_{para.test_item}_BW",
                                  str(bw))
                    # time.sleep(1)
                    x_data, y_data = n5225b.get_x_y_trace_data(1)
                    
                    x_data = [float(i) for i in x_data]
                    y_data = [float(i) for i in y_data]
                    title_section = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_number}-{VarManager().subdie_name}-{para.subdie}_SSD12"

                    curve_title = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_number}-{VarManager().subdie_name}-{para.subdie}-{para.test_item}_SSD12"
                    x_label = "Frenqucy"
                    y_label = "dB"

                    DataTransferStation.get_DTS().postarraydata("test",
                                                                result_data(title_section, para.test_item, 'line',
                                                                            False, curve_title, x_label, y_label,
                                                                            (x_data, y_data)))
                    time.sleep(1)
                    measurement_parameter = f"{para.subdie}_{para.test_item}_SSD12"
                    measurement_data = str([x_data, y_data])
                    data_unit = ""
                    data_type = "Curve"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)
                    x, y1 = n5225b.get_specific_marker_value(trace_num=2)
                    # time.sleep(2)
                    save_ini_info(constant.REMEMBER_VALUE, "remember_value", f"{section_prefix}_{para.test_item}_RL",
                                  str(y1))

                    termi_r = 50 * (1 - pow(10, float(y1) / 20)) / (1 + pow(10, float(y1) / 20))

                    measurement_parameter = f"{para.subdie}_{para.test_item}_termi_R"
                    measurement_data = str(termi_r)
                    data_unit = "ohm"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)

                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_{para.test_item}_termi_R",
                                          str(termi_r))

                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_{para.test_item}_ref_3",
                                          str(refren_value))
                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_{para.test_item}_BW", str(bw))

                    measurement_parameter = f"{para.subdie}_{para.test_item}_ref_3"
                    measurement_data = str(refren_value)
                    data_unit = "dB"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)

                    measurement_parameter = f"{para.subdie}_{para.test_item}_BW"
                    measurement_data = str(bw)
                    data_unit = "GHz"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)

                    trace2_x_data, trace2_y_data = n5225b.get_x_y_trace_data(2)
                    # time.sleep(2)
                    trace2_x_data = [float(i) for i in trace2_x_data]
                    trace2_y_data = [float(i) for i in trace2_y_data]
                    # print(trace2_x_data, trace2_y_data)
                    title_section = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_number}-{VarManager().subdie_name}-{para.subdie}_SDD22"

                    curve_title = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_number}-{VarManager().subdie_name}-{para.subdie}-{para.test_item}_SDD22"
                    x_label = "Frenqucy"
                    y_label = "dB"

                    DataTransferStation.get_DTS().postarraydata("test",
                                                                result_data(title_section, para.test_item, 'line',
                                                                            False, curve_title, x_label, y_label,
                                                                            (trace2_x_data, trace2_y_data)))
                    time.sleep(1)
                    measurement_parameter = f"{para.subdie}_{para.test_item}_SDD22"
                    measurement_data = str([trace2_x_data, trace2_y_data])
                    data_unit = ""
                    data_type = "Curve"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)

                    x, y = n5225b.get_specific_marker_value(trace_num=3)
                    # time.sleep(2)
                    save_ini_info(constant.REMEMBER_VALUE, "remember_value", f"{section_prefix}_{para.test_item}_phase",
                                  str(y))
                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_{para.test_item}_RL", str(y1))
                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_{para.test_item}_phase", str(y))
                    measurement_parameter = f"{para.subdie}_{para.test_item}_RL"
                    measurement_data = str(y1)
                    data_unit = "dB"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)

                    measurement_parameter = f"{para.subdie}_{para.test_item}_phase"
                    measurement_data = str(y)
                    data_unit = "degree"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                      measurement_parameter, measurement_data, data_unit, data_type)
            else:
                # print("No value")
                loggings.info("没有找到3db值")
                # 关闭SMU
            
    except Exception as e:
        loggings.error("pv_test3.5")
        # 抛出异常
        raise e
    finally:
        close_all_channel()


def close_all_channel():
    U2722A_App("SMU2").close_all_channel()
    U2722A_App("SMU3").close_all_channel()
    U2722A_App("SMU4").close_all_channel()
    B2901BLApp("SMU10").output_close()
    B2901BLApp("SMU11").output_close()


pv_test(locals()['para'])
